package uk.gov.swmprobation.cplitebase;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.media.ExifInterface;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.DialogFragment;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.Toast;

import com.google.analytics.tracking.android.EasyTracker;
import com.google.analytics.tracking.android.MapBuilder;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;

public class TakePhoto extends MyActivity implements ConnectionCallbacks, OnConnectionFailedListener{
	
	Camera camera;
	CameraPreview preview;
	ImageButton cross,take;
	int deviceRotation;
	String filePath;
	OrientationEventListener orientationEventListener;
	static int cameraOrientation;
	FrameLayout previewView;
	private LocationClient locationClient;
	private double lat,lng=100;
	private final static int CONNECTION_FAILURE= 999;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_take_photo);
		locationClient = new LocationClient(this, this, this);
		actionBar.hide();
		safeCameraOpen();
		preview = new CameraPreview(this, camera);
		previewView = (FrameLayout) findViewById(R.id.camera_preview);
        previewView.addView(preview);
        take = (ImageButton) findViewById(R.id.capture);
        cross = (ImageButton) findViewById(R.id.cross);
	}
	
	private void stopListener(){
		orientationEventListener.disable();
	}
	
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu items for use in the action bar
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.application_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }
	
    @Override
    protected void onPause() {
    	releaseCameraAndPreview();
      super.onPause();
    }
    
    @Override
    protected void onResume(){
    	safeCameraOpen();
    	preview = new CameraPreview(this, camera);
        previewView.addView(preview);
    	super.onResume();
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        if(checkPlayServices()){
        	locationClient.connect();
        }
    }

    @Override
    protected void onStop() {
        locationClient.disconnect();
        super.onStop();
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK)) { //Back key pressed
        	easyTracker.send(MapBuilder
	    		      .createEvent("user_action",     // Event category (required)
	    		                   "cancel_photo",  // Event action (required)
	    		                   "back_button",   // Event label
	    		                   getDuration())            // Event value
	    		      .build()
	    		  );
        }
        return super.onKeyDown(keyCode, event);
    }
    
	private boolean safeCameraOpen() {
	    boolean opened = false;
	  
	    try {
	        releaseCameraAndPreview();
	        camera = Camera.open();
	        opened = (camera != null);
	    } catch (Exception e) {
	        Log.e(getString(R.string.app_name), "failed to open Camera");
	        e.printStackTrace();
	    }

	    return opened;    
	}

	private void releaseCameraAndPreview() {
	    if (camera != null) {
	        camera.release();
	        camera = null;
	        preview = null;
	        previewView.removeAllViews();
	    }
	}
	
	public void onTake(View view) {

		EasyTracker easyTracker = EasyTracker.getInstance(this);
		
		  easyTracker.send(MapBuilder
		      .createEvent("ui_action",     // Event category (required)
		                   "button_press",  // Event action (required)
		                   "camera_button",   // Event label
		                   getDuration())            // Event value
		      .build()
		  );

		
		take.setVisibility(View.GONE);
		cross.setVisibility(View.GONE);
		camera.autoFocus(new AutoFocusCallback(){

			@Override
			public void onAutoFocus(boolean success, Camera tempCamera) {
				camera.takePicture(null, null, new PhotoHandler(TakePhoto.this));
				orientationEventListener = new OrientationEventListener(TakePhoto.this){

					@Override
					public void onOrientationChanged(int orientation) {
						deviceRotation = orientation;
						stopListener();
					}
		        };
		        orientationEventListener.enable();
			}
			
		});
	  }
	
	public void onCross(View view) {
		easyTracker.send(MapBuilder
  		      .createEvent("user_action",     // Event category (required)
  		                   "cancel_photo",  // Event action (required)
  		                   "cross_button",   // Event label
  		                   getDuration())            // Event value
  		      .build()
  		  );
		this.finish();
	  }
	
	public void confirm(byte[] data,int rotation) {
		if(lng != 100){
			if(data !=null){
				savePhoto(data,rotation);
				if(!TextUtils.isEmpty(filePath) && filePath!="" && PhotoTools.photoExists(filePath)){
					Project newproject = new Project(filePath, lat, lng);
					newproject.save();
					if (Helper.isNetworkAvailable(this)){
						easyTracker.send(MapBuilder
							      .createEvent("photo",     // Event category (required)
							                   "taken",  // Event action (required)
							                   "open_project_screen",   // Event label
							                   getDuration())            // Event value
							      .build()
							  );
				    	//If pass open next activity
					      Intent createProject = new Intent(this, CreateProject.class);
					      createProject.putExtra("id", newproject.getId());
					      startActivity(createProject);
					      this.finish();
				      } else {
				    	  easyTracker.send(MapBuilder
							      .createEvent("photo",     // Event category (required)
							                   "taken",  // Event action (required)
							                   "no_internet",   // Event label
							                   getDuration())            // Event value
							      .build()
							  );
				    	  Toast.makeText(this, "Can't access internet - Project saved to drafts.", Toast.LENGTH_LONG).show();
				    	  this.finish();
				      }
			  } else {
				  Toast.makeText(this, "Can't access photo - Please try again.", Toast.LENGTH_LONG).show();
			  }
			} else {
				Toast.makeText(this, "Error with photo - please take again", Toast.LENGTH_LONG).show();
				take.setVisibility(View.VISIBLE);
				cross.setVisibility(View.VISIBLE);
				camera.startPreview();
			}
		}else{
			Toast.makeText(this, "Can't detect your location - Please try again.", Toast.LENGTH_LONG).show();
	    	  this.finish();
		}
	}
	
	private void savePhoto(byte[] data,int rotation){
		File pictureFile = getOutputMediaFile(this);
        if (pictureFile == null){
            Log.d("TP", "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
            filePath = pictureFile.getPath();
            ExifInterface exif = new ExifInterface(filePath);
            exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(getOrientation(rotation)));
            exif.saveAttributes();
        } catch (FileNotFoundException e) {
            Log.d("TP", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("TP", "Error accessing file: " + e.getMessage());
        }
	}
	
	private int getOrientation(int tempRotation){
		int quarter = (int) Math.round(((tempRotation+cameraOrientation)/90.0));
		if (quarter > 3)
			quarter -= 4;
		switch(quarter){
			case 0:
				return ExifInterface.ORIENTATION_NORMAL;
			case 1:
				return ExifInterface.ORIENTATION_ROTATE_90;
			case 2:
				return ExifInterface.ORIENTATION_ROTATE_180;
			case 3:
				return ExifInterface.ORIENTATION_ROTATE_270;
			default:
				return ExifInterface.ORIENTATION_NORMAL;
		}
	}
	
	public class PhotoHandler implements PictureCallback {

		Context context;
		
		public PhotoHandler(Context tempContext) {
			context = tempContext;
		  }

		@Override
		public void onPictureTaken(byte[] data, Camera tempCamera) {
			confirm(data,deviceRotation);
		}
		
	}
	
	public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
	    private SurfaceHolder holder;

	    @SuppressWarnings("deprecation")
		public CameraPreview(Context context, Camera tempCamera) {
	        super(context);
	        camera = tempCamera;

	        // Install a SurfaceHolder.Callback so we get notified when the
	        // underlying surface is created and destroyed.
	        holder = getHolder();
	        holder.addCallback(this);
	        // deprecated setting, but required on Android versions prior to 3.0
	        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
	    }

	    public void surfaceCreated(SurfaceHolder holder) {
	        // The Surface has been created, now tell the camera where to draw the preview.
	        try {
	        	camera.setPreviewDisplay(holder);
	            Camera.Parameters cameraParameters = camera.getParameters();
	            //cameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
	            camera.setParameters(cameraParameters);
	            setCameraDisplayOrientation(TakePhoto.this, 0, camera);
	            camera.startPreview();
	        } catch (IOException e) {
	            Log.d("TP", "Error setting camera preview: " + e.getMessage());
	        }
	    }

	    public void surfaceDestroyed(SurfaceHolder holder) {
	        // empty. Take care of releasing the Camera preview in your activity.
	    }

	    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
	        // If your preview can change or rotate, take care of those events here.
	        // Make sure to stop the preview before resizing or reformatting it.

	        if (holder.getSurface() == null){
	          // preview surface does not exist
	          return;
	        }

	        // stop preview before making changes
	        try {
	            camera.stopPreview();
	        } catch (Exception e){
	          // ignore: tried to stop a non-existent preview
	        }

	        // set preview size and make any resize, rotate or
	        // reformatting changes here

	        // start preview with new settings
	        try {
	            camera.setPreviewDisplay(holder);
	            camera.startPreview();

	        } catch (Exception e){
	            Log.d("TP", "Error starting camera preview: " + e.getMessage());
	        }
	    }
	}
	
	@SuppressLint("SimpleDateFormat")
	private static File getOutputMediaFile(Context context){
	    // To be safe, you should check that the SDCard is mounted
	    // using Environment.getExternalStorageState() before doing this.

	    File mediaStorageDir = new File(context.getExternalFilesDir(
	              Environment.DIRECTORY_PICTURES), "GetCP");
	    // This location works best if you want the created images to be shared
	    // between applications and persist after your app has been uninstalled.

	    // Create the storage directory if it does not exist
	    if (! mediaStorageDir.exists()){
	        if (! mediaStorageDir.mkdirs()){
	            Log.d("CP", "failed to create directory");
	            return null;
	        }
	    }

	    // Create a media file name
	    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
	    File mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg");
	    
	    return mediaFile;
	}
	
	@TargetApi(Build.VERSION_CODES.GINGERBREAD)
	private static void setCameraDisplayOrientation(Activity activity,
	         int cameraId, android.hardware.Camera tempCamera) {
		
		int result= 90; 
		int cameraResult= 90;
		if(Build.VERSION.SDK_INT != Build.VERSION_CODES.FROYO){
	     android.hardware.Camera.CameraInfo info =
	             new android.hardware.Camera.CameraInfo();
	     android.hardware.Camera.getCameraInfo(cameraId, info);
	     int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
	     int degrees = 0;
	     switch (rotation) {
	         case Surface.ROTATION_0: degrees = 0; cameraResult = 0; break;
	         case Surface.ROTATION_90: degrees = 90; cameraResult = 90; break;
	         case Surface.ROTATION_180: degrees = 180; cameraResult = 180; break;
	         case Surface.ROTATION_270: degrees = 270; cameraResult = 270; break;
	     }

	      result = (info.orientation - degrees + 360) % 360;
		}
		cameraOrientation = cameraResult+result;
	     tempCamera.setDisplayOrientation(result);
	 }

	@TargetApi(Build.VERSION_CODES.GINGERBREAD)
	private static int getCameraOrientation(Activity activity,
	         int cameraId, android.hardware.Camera tempCamera){
		int result= 90; 
		if(Build.VERSION.SDK_INT != Build.VERSION_CODES.FROYO){
		     android.hardware.Camera.CameraInfo info =
		             new android.hardware.Camera.CameraInfo();
		     android.hardware.Camera.getCameraInfo(cameraId, info);
		     int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
		     switch (rotation) {
		         case Surface.ROTATION_0: result = 0; break;
		         case Surface.ROTATION_90: result = 90; break;
		         case Surface.ROTATION_180: result = 180; break;
		         case Surface.ROTATION_270: result = 270; break;
		     }
		}
		return result;
	}

	private boolean checkPlayServices(){
		int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
		if (ConnectionResult.SUCCESS == resultCode) {
            return true;
        } else {
        	Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, CONNECTION_FAILURE);
        	if (errorDialog != null) {
                // Create a new DialogFragment for the error dialog
                ErrorDialogFragment errorFragment = new ErrorDialogFragment();
                // Set the dialog in the DialogFragment
                errorFragment.setDialog(errorDialog);
                // Show the error dialog in the DialogFragment
                errorFragment.show(getSupportFragmentManager(),
                        "Location Updates");
            }
        	return false;
        }
	}
    
	 public static class ErrorDialogFragment extends DialogFragment {
	        // Global field to contain the error dialog
	        private Dialog mDialog;
	        // Default constructor. Sets the dialog field to null
	        public ErrorDialogFragment() {
	            super();
	            mDialog = null;
	        }
	        // Set the dialog to display
	        public void setDialog(Dialog dialog) {
	            mDialog = dialog;
	        }
	        // Return a Dialog to the DialogFragment.
	        @Override
	        public Dialog onCreateDialog(Bundle savedInstanceState) {
	            return mDialog;
	        }
	    }
	
	@Override
	public void onConnectionFailed(ConnectionResult result) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onConnected(Bundle connectionHint) {
		lat = locationClient.getLastLocation().getLatitude();
        lng = locationClient.getLastLocation().getLongitude();
	}

	@Override
	public void onDisconnected() {
		// TODO Auto-generated method stub
		
	}
}
